]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m
mDNSResponder-1096.40.7.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Tests / Unit Tests / CacheOrderTest.m
1 /*
2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "unittest_common.h"
18 #import <XCTest/XCTest.h>
19
20 struct UDPSocket_struct
21 {
22 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
23 };
24 typedef struct UDPSocket_struct UDPSocket;
25
26 // This client request was generated using the following command: "dns-sd -Q web.mydomain.test".
27 uint8_t test_order_query_msgbuf[30] = {
28 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x65, 0x62, 0x2e, 0x6d, 0x79, 0x64,
29 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x01, 0x00, 0x01
30 };
31 #if 0
32 0000 10 c1 01 00 00 01 00 00 00 00 00 00 03 77 65 62
33 0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00
34 0020 01 00 01
35
36 0000 ef 53 01 00 00 01 00 00 00 00 00 00 03 77 65 62
37 0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00
38 0020 01 00 01
39
40 uint8_t test_query_client_msgbuf[35] = {
41 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
42 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
43 0x01, 0x00, 0x01
44 };
45 #endif
46 // This uDNS message is a canned response that was originally captured by wireshark.
47 uint8_t test_order_response1_msgbuf[228] = {
48 0x0f, 0x98, // transaction id
49 0x85, 0x80, // flags
50 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN
51 0x00, 0x04, // 4 anwsers: Addr 10.0.0.101, Addr 10.0.0.105, Addr 10.0.0.104, Addr 10.0.0.102
52 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test
53 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23
54 0x03, 0x77, 0x65, 0x62,
55 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00,
56 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
57 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
58 0x00, 0x00, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
59 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
60 0x00, 0x00, 0x66, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02,
61 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04,
62 0xc0, 0xa8, 0x00, 0x17
63 };
64
65 // This uDNS message is a canned response that was originally captured by wireshark, then modified to match above (other than Addr order).
66 uint8_t test_order_response2_msgbuf[228] = {
67 0x0f, 0x98, // transaction id
68 0x85, 0x80, // flags
69 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN
70 0x00, 0x04, // 4 anwsers: Addr 10.0.0.102, Addr 10.0.0.101, Addr 10.0.0.104, Addr 10.0.0.105
71 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test
72 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23
73 0x03, 0x77, 0x65, 0x62,
74 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00,
75 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
76 0x00, 0x00, 0x66, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
77 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
78 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
79 0x00, 0x00, 0x69, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02,
80 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04,
81 0xc0, 0xa8, 0x00, 0x17
82 };
83
84 // Variables associated with contents of the above uDNS message
85 char test_order_domainname_cstr[] = "web.mydomain.test.";
86
87 @interface CacheOrderTest : XCTestCase
88 {
89 UDPSocket* local_socket;
90 request_state* client_request_message;}
91 @end
92
93 @implementation CacheOrderTest
94
95 // The InitThisUnitTest() initializes the mDNSResponder environment as well as
96 // a DNSServer. It also allocates memory for a local_socket and client request.
97 // Note: This unit test does not send packets on the wire and it does not open sockets.
98 - (void)setUp
99 {
100 mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS));
101
102 // Init unit test environment and verify no error occurred.
103 mStatus result = init_mdns_environment(mDNStrue);
104 XCTAssertEqual(result, mStatus_NoError);
105
106 // Add one DNS server and verify it was added.
107 AddDNSServer_ut();
108 XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1);
109
110 // Create memory for a socket that is never used or opened.
111 local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket));
112
113 // Create memory for a request that is used to make this unit test's client request.
114 client_request_message = calloc(1, sizeof(request_state));
115 }
116
117 - (void)tearDown
118 {
119 mDNS *m = &mDNSStorage;
120 request_state* req = client_request_message;
121 DNSServer *ptr, **p = &m->DNSServers;
122
123 while (req->replies)
124 {
125 reply_state *reply = req->replies;
126 req->replies = req->replies->next;
127 mDNSPlatformMemFree(reply);
128 }
129 mDNSPlatformMemFree(req);
130
131 mDNSPlatformMemFree(local_socket);
132
133 while (*p)
134 {
135 ptr = *p;
136 *p = (*p)->next;
137 LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
138 mDNSPlatformMemFree(ptr);
139 }
140 }
141
142 - (void)testSuspiciousReplyTestSeries
143 {
144 [self _clientQueryRequest];
145 [self _verifyCacheOrderBehavior];
146 }
147
148 // Simulate a uds client request by setting up a client request and then
149 // calling mDNSResponder's handle_client_request. The handle_client_request function
150 // processes the request and starts a query. This unit test verifies
151 // the client request and query were setup as expected. This unit test also calls
152 // mDNS_execute which determines the cache does not contain the new question's
153 // answer.
154 - (void)_clientQueryRequest
155 {
156 mDNS *const m = &mDNSStorage;
157 request_state* req = client_request_message;
158 char *msgptr = (char *)test_order_query_msgbuf;
159 size_t msgsz = sizeof(test_order_query_msgbuf);
160 mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
161 DNSQuestion *q;
162 mStatus err = mStatus_NoError;
163 char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
164
165 // Process the unit test's client request
166 start_client_request(req, msgptr, msgsz, query_request, local_socket);
167 XCTAssertEqual(err, mStatus_NoError);
168
169 // Verify the request fields were set as expected
170 XCTAssertNil((__bridge id)req->next);
171 XCTAssertNil((__bridge id)req->primary);
172 XCTAssertEqual(req->sd, client_req_sd);
173 XCTAssertEqual(req->process_id, client_req_process_id);
174 XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name));
175 XCTAssertEqual(req->validUUID, mDNSfalse);
176 XCTAssertEqual(req->errsd, 0);
177 XCTAssertEqual(req->uid, client_req_uid);
178 XCTAssertEqual(req->ts, t_complete);
179 XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
180 XCTAssertEqual(req->msgend, msgptr+msgsz);
181 XCTAssertNil((__bridge id)(void*)req->msgbuf);
182 XCTAssertEqual(req->hdr.version, VERSION);
183 XCTAssertNil((__bridge id)req->replies);
184 XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
185 XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates);
186 XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny);
187
188 // Verify the query fields were set as expected
189 q = &req->u.queryrecord.op.q;
190 XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL);
191 XCTAssertEqual(q, m->Questions);
192 XCTAssertEqual(q, m->NewQuestions);
193 XCTAssertEqual(q->SuppressUnusable, mDNSfalse);
194 XCTAssertEqual(q->ReturnIntermed, mDNStrue);
195 XCTAssertEqual(q->Suppressed, mDNSfalse);
196
197 ConvertDomainNameToCString(&q->qname, qname_cstr);
198 XCTAssertFalse(strcmp(qname_cstr, test_order_domainname_cstr));
199 XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
200
201 XCTAssertEqual(q->InterfaceID, mDNSInterface_Any);
202 XCTAssertEqual(q->flags, req->flags);
203 XCTAssertEqual(q->qtype, 1);
204 XCTAssertEqual(q->qclass, 1);
205 XCTAssertEqual(q->LongLived, 0);
206 XCTAssertEqual(q->ExpectUnique, mDNSfalse);
207 XCTAssertEqual(q->ForceMCast, 0);
208 XCTAssertEqual(q->TimeoutQuestion, 0);
209 XCTAssertEqual(q->WakeOnResolve, 0);
210 XCTAssertEqual(q->UseBackgroundTraffic, 0);
211 XCTAssertEqual(q->ValidationRequired, 0);
212 XCTAssertEqual(q->ValidatingResponse, 0);
213 XCTAssertEqual(q->ProxyQuestion, 0);
214 XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
215 XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
216 XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
217 XCTAssertEqual(q->AppendSearchDomains, 0);
218 XCTAssertNil((__bridge id)q->DuplicateOf);
219
220 // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
221 // It won't be yet because the cache is empty.
222 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
223 mDNS_Execute(m);
224
225 // Verify mDNS_Execute processed the new question.
226 XCTAssertNil((__bridge id)m->NewQuestions);
227
228 // Verify the cache is empty and the request got no reply.
229 XCTAssertEqual(m->rrcache_totalused, 0);
230 XCTAssertNil((__bridge id)req->replies);
231 }
232
233 // This unit test performs two queries and verifies the cache oredr is updated on a new response.
234 // 1) Verify response is ordered in the cache as expected
235 // 2) Test again with new response, and verify cache order is updated
236 - (void)_verifyCacheOrderBehavior
237 {
238 mDNS *const m = &mDNSStorage;
239 DNSMessage *msgptr;
240 size_t msgsz;
241 request_state* req = client_request_message;
242 DNSQuestion *q = &req->u.queryrecord.op.q;
243 mStatus status;
244
245 // 1)
246 // Process first response
247 // Verify response cache count & order
248
249 msgptr = (DNSMessage *)test_order_response1_msgbuf;
250 msgsz = sizeof(test_order_response1_msgbuf);
251 receive_response(req, msgptr, msgsz);
252
253 // Verify records received
254 mDNSu32 CacheUsed =0, notUsed =0;
255 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
256 XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group
257
258 // Verify record order
259 mDNSu8 lastoctet1[4] = {101, 105, 104, 102};
260 status = verify_cache_addr_order_for_domain_ut(m, lastoctet1, 4, &q->qname);
261 XCTAssertEqual(status, mStatus_NoError, @"Cache order test 1 failed");
262
263 // 2)
264 // Process second response
265 // Verify response cache count & order
266
267 msgptr = (DNSMessage *)test_order_response2_msgbuf;
268 msgsz = sizeof(test_order_response2_msgbuf);
269 receive_response(req, msgptr, msgsz);
270
271 // Verify records received
272 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
273 XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group
274
275 // Verify record order
276 mDNSu8 lastoctet2[4] = {102, 101, 104, 105};
277 status = verify_cache_addr_order_for_domain_ut(m, lastoctet2, 4, &q->qname);
278 XCTAssertEqual(status, mStatus_NoError, @"Cache order test 2 failed");
279 }
280
281
282 @end